// utf8 中文

if (! self.TETRISOK) {
    var TetrisObjects = new Array();
    var InputStatus = new Array(4);
    var KeyPress = new Array(4);
}

function Game_Tetris(dName, Mode, BlLine, Inline, Info) {
    this.DisplayObject = document.getElementById(dName);
    if (! this.DisplayObject) return;

    TetrisObjects[dName] = this;
    this.NFCmd = 'TetrisObjects["'+dName+'"].NextFrame()';

    this.InitBlockSpace = function() {
        this.BlockSpace = TwoDArray(this.GamePlaceX + 2, this.GamePlaceY + 1);
        for (I=0;I<this.BlockSpace.length;I++) this.BlockSpace[I][this.GamePlaceY] = 1;
        for (I=0;I<this.GamePlaceY+1;I++) {
            this.BlockSpace[0][I] = 1;
            this.BlockSpace[this.BlockSpace.length-1][I] = 1;
        }
    }

    this.SetXY = function(O, X, Y) {
        O.style.left = X * this.BlWidth + 'px';
        O.style.top = Y * this.BlHeight + 'px';
    }

    this.SetWH = function(O, X, Y) {
        O.style.width = X * this.BlWidth + 'px';
        O.style.height = Y * this.BlHeight + 'px';
    }

    this.Start = function() {
        if (this.DisplayObject.SObj) this.BlLine = this.DisplayObject.SObj.BlLine.join(',').split(',');

        while (O = this.Pre.shift()) {
            O.Delete();
            delete O;
        }

        if (this.GameBL) {
            this.GameBL.Delete();
            this.GameBL = 0;
        }

        if (this.NFT) {
            clearTimeout(this.NFT);
            this.NFT = 0;
        }

        this.DelayF = 0;
        this.DownScore = 0;
        this.State = 1;
        this.CurrentFrame = 0;

        this.Pre.push(new Tetris(this.PrePlace, this.TBase, this.BlWidth, this.BlHeight, this.RecordBL(), 1, 1));
        this.Pre.push(new Tetris(this.PrePlace, this.TBase, this.BlWidth, this.BlHeight, this.RecordBL(), 1, 5));
        this.SetScore();
        this.LevelText.innerHTML = '等級 0';
        this.InitBlockSpace();
        if (this.DisplayObject.SObj) this.DisplayObject.SObj.Start();
        this.NextFrame();
    }

    this.RecordBL = function() {
        B = (this.BlLine && this.BlLine.length) ? this.BlLine.pop(): 0;
        B = B ? B : (1 + Math.floor(Math.random() * 6));
        this.RecBl += (B + ',');
        return B;
    }

    this.End = function() {
        this.State = 0;
        if (this.RecKey) {
            alert(this.DisplayObject.SObj ? '挑戰失敗!' : (this.MaxFrame ? '時間到!' : '你已經死了!'));
            O = document.createElement('form');
            O.method = 'POST';
            O.style.display = 'none';
            O.innerHTML = '<input name="KE" value="'+ this.RecKey + '" /><input name="BL" value="'+ this.RecBl + '" /><input name="SC" value="'+ this.Score + '" /><input name="MO" value="'+ this.Mode + '" />';
            this.PostRec = this.DisplayObject.appendChild(O);
            this.PostRec.submit();
        }
    }

    this.NextBL = function() {
        this.Level = Math.floor(this.Score / 60000);
        this.LevelText.innerHTML = '等級 ' + this.Level;
        this.SpeedF = (this.Mode&8) ? 2 : Math.max(31 - this.Level, 2);
        this.DownScore = 0;
        this.GameBL = this.Pre.shift();
        this.Pre[0].Move(1,1);
        this.Pre.push(new Tetris(this.PrePlace, this.TBase, this.BlWidth, this.BlHeight, this.RecordBL(), 1, 5));
        this.GameBL.Move(4,0,this.GamePlace);
        if (! this.Test(0, 0, 0)) this.End();
    }

    this.NextFrame = function() {
        if (this.State) {
            this.CurrentFrame++;
            if (this.MaxFrame && (this.MaxFrame < this.CurrentFrame)) this.End();

            if (! this.GameBL) this.NextBL();

            this.DelayF++;
            this.DelayF %= this.SpeedF;

            this.GetInput();

            if (this.State && (this.DelayF == 0)) this.TestDown();

            this.NFT = setTimeout(this.NFCmd, 50);
        }
    }

    this.TestDown = function() {
        if (this.Test(0, 1, 0)) {
            this.GameBL.TY++;
            this.GameBL.Move();
            this.AddScore(1 + this.DownScore);
        } else {
            for (I=0;I<4;I++) {
                this.BlockSpace[this.GameBL.TestXY[I][0]+1][this.GameBL.TestXY[I][1]-1] = this.GameBL.BL[I];
                this.BlockSpace[0][this.GameBL.TestXY[I][1]-1]++;
            }
            this.GameBL = 0;
            this.Destory();
        }
    }

    this.Debug = function() {
        OUT = 'x';
        for (I=this.GamePlaceY-1;I>=2;I--) {
            OUT += (','+this.BlockSpace[0][I]);
        }
        alert(OUT);
    }

    this.Destory = function() {
        DY = 0;
        for (I=this.GamePlaceY-1;I>=2;I--) {
            while (this.BlockSpace[0][I - DY] == this.BlockSpace.length - 1) {
                DY++;
            }
            if (DY) {
                for (J=1;J<this.BlockSpace.length-1;J++) {
                    if (this.BlockSpace[J][I]) this.BlockSpace[J][I].Delete();
                    this.BlockSpace[J][I] = this.BlockSpace[J][I - DY];
                    this.BlockSpace[J][I - DY] = 0;
                    if (this.BlockSpace[J][I]) this.BlockSpace[J][I].SetXY(J - 1, I);
                }
                this.BlockSpace[0][I] = this.BlockSpace[0][I - DY] ? this.BlockSpace[0][I - DY] : 1;
                this.BlockSpace[0][I - DY] = 1;
            }
        }
        this.AddScore((10 + DY * DY * 100) * (this.DownScore + 1));
    }

    this.Test = function(X, Y, R) {
        this.GameBL.Test(X, Y, R);
        for (I=0;I<4;I++) if (this.BlockSpace[this.GameBL.TestXY[I][0]+1][this.GameBL.TestXY[I][1]]) return false;
        return true;
    }

    this.GetInput = function() {
        if (this.InputDevice) {
            if (IN = this.InputDevice.pop()) {
                if (IN.match(/1/)) this.KeyLeft();
                if (IN.match(/2/)) this.KeyRoll();
                if (IN.match(/3/)) this.KeyRight();
                if (IN.match(/4/)) this.KeyDown();
            }
        } else {
            KeyPress[0] && this.RecordKey(1) && this.KeyLeft();
            KeyPress[1] && this.RecordKey(2) && this.KeyRoll();
            KeyPress[2] && this.RecordKey(3) && this.KeyRight();
            KeyPress[3] && this.RecordKey(4) && this.KeyDown();
            this.RecordKey(',');
            for (I=0;I<4;I++) KeyPress[I] = 0;
        }
    }

    this.RecordKey = function(K) {
        this.RecKey += K;
        return 1;
    }

    this.KeyLeft = function() {
        if (this.Test(-1, 0, 0)) {
            this.GameBL.TX--;
            this.GameBL.Move();
        }
    }

    this.KeyRoll = function() {
        if (this.Test(0, 0, 1)) {
            this.GameBL.Roll();
            this.GameBL.Move();
        }
    }

    this.KeyRight = function() {
        if (this.Test(1, 0, 0)) {
            this.GameBL.TX++;
            this.GameBL.Move();
        }
    }

    this.KeyDown = function() {
        this.DownScore = this.Level * 1 + 1;
        this.SpeedF = 1;
    }

    this.SetScore = function(S) {
        this.Score = S ? S : 0;
        this.ScoreText.innerHTML = this.Score;
    }

    this.AddScore = function(S) {
        this.Score += S * 1;
        this.ScoreText.innerHTML = this.Score;
    }

    this.KeyDownEvent = function(E) {
        switch(E.keyCode) {
            case 37:
            case 38:
            case 39:
            case 40:
                InputStatus[E.keyCode-37] = 1;
                KeyPress[E.keyCode-37] = 1;
                if (E.preventDefault) E.preventDefault();
                return false;
        }
    }

    this.KeyUpEvent = function(E) {
        switch(E.keyCode) {
            case 37:
            case 38:
            case 39:
            case 40:
                InputStatus[E.keyCode-37] = 0;
                break;
        }
    }

    this.TimeLine = 0;
    this.GamePlaceX = 11;
    this.GamePlaceY = 20;

    this.Mode = Mode;
    this.BlWidth = (Mode&1) ? 5 : 20;
    this.BlHeight = (Mode&1) ? 5 : 20;
    this.MaxFrame = (Mode&2) ? 1200 : 0;
    this.MaxFrame = (Mode&4) ? 2400 : this.MaxFrame;

    this.DisplayH = this.BlHeight * 22;
    this.DisplayW = this.BlWidth * 20;

    this.Pre = new Array();
    this.GameBL = 0;
    this.NFT = 0;
    this.InputDevice = Inline ? Inline.split(',').reverse() : 0;
    this.BlLine = BlLine ? BlLine.split(',').reverse() : 0;
    this.RecKey = '';
    this.RecBl = '';

    this.State = 0;

    this.TBase = new Array(new Array('#44f', 2, 0, 1, 1, 1, 2, 1, 3, 1, 1, 0, 1, 1, 1, 2, 1, 3), new Array('#ff4', 1, 1, 1, 1, 2, 2, 1, 2, 2), new Array('#f4f', 2, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 2, 1, 1, 1, 1, 2), new Array('#4ff', 2, 0, 2, 1, 2, 1, 1, 2, 1, 1, 0, 1, 1, 2, 1, 2, 2), new Array('#4f4', 4, 0, 1, 1, 1, 2, 1, 2, 0, 0, 0, 1, 0, 1, 1, 1, 2, 0, 2, 0, 1, 1, 1, 2, 1, 1, 0, 1, 1, 1, 2, 2, 2), new Array('#f44', 4, 0, 0, 0, 1, 1, 1, 2, 1, 0, 2, 1, 0, 1, 1, 1, 2, 0, 1, 1, 1, 2, 1, 2, 2, 1, 0, 2, 0, 1, 1, 1, 2));

    O = document.createElement('style');
    this.StyleRules = document.body.appendChild(O);

    AddStyleRule('div#'+this.DisplayObject.id+' H7', 'height: '+(this.BlHeight-1)+'px;width: '+(this.BlWidth-1)+'px;border: 1px solid #808080;position: absolute;font-size:0');
    AddStyleRule('div#'+this.DisplayObject.id+' DIV H1', 'color: #FFFFFF;margin: 5%;border:0;background: transparent;font-size:'+((Mode&1) ? 1 : 11)+'px;font-family:Courier;padding:0');
    AddStyleRule('div#'+this.DisplayObject.id+' INPUT', 'font-size:'+((Mode&1) ? 8 : 11)+'px;width:80%;height:auto;line-height:100%;');
    this.DisplayObject.style.cssText = 'font-family: monospace;font-size: '+((Mode&1) ? 1 : 11)+'px;height: '+this.DisplayH+'px;width: '+this.DisplayW+'px;background-color: #A0A0A0;position: relative';

    O = document.createElement('div');
    O.id = 'game_place';
    O.style.cssText = 'background-color: #000000;border: 1px solid #FFFFFF;position: absolute;padding:0';
    this.SetWH(O, this.GamePlaceX, this.GamePlaceY);
    this.SetXY(O, 1, 1);
    this.GamePlace = this.DisplayObject.appendChild(O);

    O = document.createElement('div');
    O.id = 'pre_place';
    O.style.cssText = 'background-color: #404040;border: 1px solid #C0C0C0;position: absolute;padding:0';
    this.SetWH(O, 6, 9);
    this.SetXY(O, this.GamePlaceX + 2, 1);
    this.PrePlace = this.DisplayObject.appendChild(O);

    O = document.createElement('div');
    O.id = 'score_place';
    O.style.cssText = 'background-color: #402020;position: absolute;color: #A0A0FF; text-align: center';
    O.innerHTML = '<h1>向上俄羅斯</h1>' + (Info ? Info : '') + (this.InputDevice ? '' : '<div style="width:65%">請按↑↓←→進行遊戲</div>');
    this.SetWH(O, 6, 10);
    this.SetXY(O, this.GamePlaceX + 2, 11);
    this.ScorePlace = this.DisplayObject.appendChild(O);

    O = document.createElement('div');
    O.style.cssText = 'background-color: #000000;color: #C0FFFF; text-align: right; margin: 10%;font-size: '+((Mode&1) ? 6 : 11)+'px;';
    this.ScoreText = this.ScorePlace.appendChild(O);

    O = document.createElement('div');
    O.style.cssText = 'background-color: #000000;color: #80FF80; text-align: center; margin: 10%;font-size: '+((Mode&1) ? 6 : 11)+'px;';
    this.LevelText = this.ScorePlace.appendChild(O);

    if (! this.InputDevice) {
        AddEvent('keydown', this.KeyDownEvent);
        AddEvent('keyup', this.KeyUpEvent);

        O = document.createElement('input');
        O.type = 'button';
        O.value = (Mode&1) ? 'GO' : '開始';
        O.TObj = this;
        O.onclick = function() {CheckLogin() && (this.style.display = 'none') && this.TObj.Start()};

        this.ScorePlace.appendChild(O);
    }

    this.DisplayObject.TObj = this;
    this.DisplayObject.focus();
}

function AddEvent(E,F) {
    if (document.addEventListener) document.addEventListener(E, F, false);
    else document.attachEvent('on'+E, F);
}

function Game_BL(C, W, H, O, X, Y) {
    this.PObj = 0;
    this.DObj = document.createElement('h7');
    this.DObj.style.backgroundColor = C;
    this.BlWidth = W;
    this.BlHeight = H;

    this.SetXY = function(X, Y, O) {
        this.DObj.style.left = X * this.BlWidth + 'px';
        this.DObj.style.top = Y * this.BlHeight + 'px';
        if (O) this.SetParent(O);
    }

    this.SetParent = function(O) {
        if (O) {
            if (this.PObj) this.PObj.removeChild(this.DObj);
            this.PObj = O;
            O.appendChild(this.DObj);
        }
    }

    this.Delete = function() {
        this.PObj.removeChild(this.DObj);
        delete this.DObj;
    }

    if (O) this.SetXY(X, Y, O);
}

function Tetris(O, B, W, H, T, X, Y) {

    this.Roll = function(W) {
        this.Status += (W ? 1 : this.AllStatus - 1);
        this.Status %= this.AllStatus;
        this.Move();
    }

    this.Move = function(X, Y, O) {
        if (X || Y) {
            this.TX = X;
            this.TY = Y;
        }
        this.Test(0, 0, 0);
        for (I=0;I<4;I++) this.BL[I].SetXY(this.TestXY[I][0], this.TestXY[I][1], O);
    }

    this.Test = function(X, Y, S) {
        SS = (this.Status + S) % this.AllStatus;
        for (I=0;I<4;I++) {
            this.TestXY[I][0] = this.TX + X + this.TBase[SS*8+I*2+2];
            this.TestXY[I][1] = this.TY + Y + this.TBase[SS*8+I*2+3];
        }
    }

    this.Delete = function() {
        for (I=0;I<4;I++) this.BL[I].Delete();
        delete this.BL;
    }

    this.Place = O;
    this.TType = T ? T : 1 + Math.floor(Math.random() * 6);
    this.TBase = B[this.TType-1];
    this.Color = this.TBase[0];
    this.AllStatus = this.TBase[1];
    this.Status = 0;
    this.TX = X ? X : 0;
    this.TY = Y ? Y : 0;
    this.BL = new Array();
    this.TestXY = TwoDArray(4, 2);
    for (I=0;I<4;I++) this.BL.push(new Game_BL(this.Color, W, H, this.Place, this.TX + this.TBase[I*2+2], this.TY + this.TBase[I*2+3]));
}

function TwoDArray(X, Y) {
    var O = new Array();
    for (I = 0;I < X;I++) O.push(new Array(Y));
    return O;
}

function AddStyleRule(S, T) {
    if (document.styleSheets[0].addRule) document.styleSheets[0].addRule(S, T);
    else document.styleSheets[0].insertRule(S + ' {' + T + '}', 0);
}

TETRISOK = 1;